/*********************************************************************************************************************
 * COPYRIGHT NOTICE
 * Copyright (c) 2018,逐飞科技
 * All rights reserved.
 * 技术讨论QQ群：	一群：179029047(已满)
 *					二群：244861897(已满)
 *					三群：824575535
 *
 * 以下所有内容版权均属逐飞科技所有，未经允许不得用于商业用途，
 * 欢迎各位使用并传播本程序，修改内容时必须保留逐飞科技的版权声明。
 *
 * @file			zf_adc.c
 * @company			成都逐飞科技有限公司
 * @author			逐飞科技(QQ3184284598)
 * @version			查看doc内version文件 版本说明
 * @Software		IAR 8.3 or MDK 5.24
 * @Taobao			https://seekfree.taobao.com/
 * @date			2020-03-25
 * @note			本文件作为 LPC55S 系列芯片开源库外设文件
					提供 ADC 外设驱动
 ********************************************************************************************************************/

#include "zf_adc.h"
#include "fsl_power.h"

static bool adc_init = false; 
//-------------------------------------------------------------------------------------------------------------------
//	@brief		ADC 获取默认配置
//	@param		config			配置结构体指针
//	Sample usage:				zf_adc_get_default_config(config);
//	@note			这里会开启 ADC 默认开启预启动 方便后续工作
//					相对应的会增加功耗 徒增功耗 * 1 用户可以通过参数设置进行修改
//-------------------------------------------------------------------------------------------------------------------
void zf_adc_get_default_config (lpadc_config_t *config)
{

//	config->enableInDozeMode			= true;																			// 开启 Doze 模式 允许 ADC 转换立即停止进入等待 否则 ADC 将等待当前平均采样并迭代 FIFO 完成后才停止或进入等待
//	config->conversionAverageMode		= kLPADC_ConversionAverage1;													// 直接输出单次转换 ADC 不进行平均采样
//	config->enableAnalogPreliminary		= false;																		// 预启动 开启则 ADC 常工作 没有转换延迟 代价是功耗 关闭则会有一定启动转换的延迟
//	config->powerUpDelay				= 0x80;																			// 启动延时 没有开启预启动的话 触发 ADC 转换就会存在这么个延时 ADCK 周期就会存在比这个更长的延迟 4*powerdelay
//	config->referenceVoltageSource		= kLPADC_ReferenceVoltageAlt1;													// 选择基准电压
//	config->powerLevelMode				= kLPADC_PowerLevelAlt1;														// ADC 电源功耗设置？
//	config->triggerPriorityPolicy		= kLPADC_TriggerPriorityPreemptImmediately;										// 转换优先级设置
//	config->enableConvPause				= false;																		// 转换间延迟是否启用
//	config->convPauseDelay				= 0U;																			// 转换间延迟
//	config->FIFO0Watermark				= 0U;																			// ADC FIFO0 条目设置
//	config->FIFO1Watermark				= 0U;																			// ADC FIFO1 条目设置

	LPADC_GetDefaultConfig(config);
	config->enableAnalogPreliminary		= true;
	config->referenceVoltageSource		= kLPADC_ReferenceVoltageAlt2;
}

//-------------------------------------------------------------------------------------------------------------------
//	@brief		ADC 配置参数修改
//	@param		config			配置结构体指针
//	@param		index			指定修改参数索引
//	@param		data			参数值
//	Sample usage:				zf_adc_param_set(&config, ADC_PARAM_DOZE_MODE, ADC_DOZE_MODE_ENANLE);
//-------------------------------------------------------------------------------------------------------------------
void zf_adc_param_set (lpadc_config_t *config, adc_param_list index, uint32_t data)
{
	switch(index)
	{
		case ADC_PARAM_DOZE_MODE:
			config->enableInDozeMode			= (bool)data;
			break;
		case ADC_PARAM_AVERAGE_MODE:
			config->conversionAverageMode		= (lpadc_conversion_average_mode_t)data;
			break;
		case ADC_PARAM_PRELIMINARY_ENABLE:
			config->enableAnalogPreliminary		= (bool)data;
			break;
		case ADC_PARAM_POWER_DELAY:
			config->powerUpDelay				= data;
			break;
		case ADC_PARAM_REF_SELECT:
			config->referenceVoltageSource		= (lpadc_reference_voltage_source_t)data;
			break;
		case ADC_PARAM_POWER_LEVEL:
			config->powerLevelMode				= (lpadc_power_level_mode_t)data;
			break;
		case ADC_PARAM_PRIORITY_POLICY:
			config->triggerPriorityPolicy		= (lpadc_trigger_priority_policy_t)data;
			break;
		case ADC_PARAM_PAUSE_ENABLE:
			config->enableConvPause				= (bool)data;
			break;
		case ADC_PARAM_PAUSE_DELAY:
			config->convPauseDelay				= data;
			break;
		case ADC_PARAM_FIFO0_MARK:
			config->FIFO0Watermark				= data;
			break;
		case ADC_PARAM_FIFO1_MARK:
			config->FIFO1Watermark				= data;
			break;
		default:
			break;
	}
}

//-------------------------------------------------------------------------------------------------------------------
//	@brief		ADC 获取触发命令默认配置
//	@param		config			配置结构体指针
//	Sample usage:				zf_adc_convcmd_get_default_config(&config);
//-------------------------------------------------------------------------------------------------------------------
void zf_adc_convcmd_get_default_config (lpadc_conv_command_config_t *config)
{
//	config->sampleChannelMode			= kLPADC_SampleChannelSingleEndSideA;											// 这个变量写入到 CMDL 的 [6:5]CTYPE 寄存器 是转换模式 A/B 部分转换或者 A|B 的差分 或者 A B 独立转换
//	config->channelNumber				= 0U;																			// 这个变量写入到 CMDL 的 [4:0]ADCH 寄存器 是选择输入通道
//	config->enableAutoChannelIncrement	= false;																		// 这个变量写入到 CMDH 的 [7]LWI 寄存器 循环与增量的使能 寄存器描述跟没有差不多
//	config->loopCount					= 0U;																			// 这个变量写入到 CMDH 的 [19:16]LOOP 寄存器 是命令的重复执行次数
//	config->hardwareAverageMode			= kLPADC_HardwareAverageCount1;													// 这个变量写入到 CMDH 的 [14:12]AVGS 寄存器 是硬件转换平均数级别
//	config->sampleTimeMode				= kLPADC_SampleTimeADCK3;														// 这个变量写入到 CMDH 的 [10:8]STS 寄存器 采样时间
//	config->hardwareCompareMode			= kLPADC_HardwareCompareDisabled;												// 这个变量写入到 CMDH 的 [1:0]CMPEN 寄存器 比较模式设置
//	config->hardwareCompareValueHigh	= 0U;																			// 这个变量写入到 CV 的 [31:16]CVH 寄存器 设置比较值的最大值？
//	config->hardwareCompareValueLow		= 0U;																			// 这个变量写入到 CV 的 [15:0]CVL 寄存器 设置比较值的最小值？
//	config->conversionResolutionMode	= kLPADC_ConversionResolutionStandard;											// 这个变量写入到 CMDL 的 [7]MODE 寄存器 是选择分辨率的
//	config->enableWaitTrigger			= false;																		// 这个变量写入到 CMDH 的 [2]WAIT_TRIG 寄存器 信号断言使能？

	LPADC_GetDefaultConvCommandConfig(config);
	config->conversionResolutionMode	= (lpadc_conversion_resolution_mode_t)ADC_RESOLUTION_MODE_16BIT;
}

//-------------------------------------------------------------------------------------------------------------------
//	@brief		ADC 触发命令配置参数修改
//	@param		config			配置结构体指针
//	@param		index			指定修改参数索引
//	@param		data			参数值
//	Sample usage:				zf_adc_convcmd_param_set(&config, ADC_CONVTRIGGER_PARAM_CHB_FIFOSET, ADC_FIFOSET_0);
//-------------------------------------------------------------------------------------------------------------------
void zf_adc_convcmd_param_set (lpadc_conv_command_config_t *config, adc_convcmd_param_list index, uint32_t data)
{
	switch(index)
	{
		case ADC_CONVCMD_PARAM_SAMPLE_MODE:
			config->sampleChannelMode			= (lpadc_sample_channel_mode_t)data;
			break;
		case ADC_CONVCMD_PARAM_CHANNEL_NUM:
			config->channelNumber				= data;
			break;
		case ADC_CONVCMD_PARAM_NEXT_CMD:
			config->chainedNextCommandNumber	= data;
			break;
		case ADC_CONVCMD_PARAM_AUTO_INCREMENT:
			config->enableAutoChannelIncrement	= (bool)data;
			break;
		case ADC_CONVCMD_PARAM_CMD_LOOP:
			config->loopCount					= data;
			break;
		case ADC_CONVCMD_PARAM_HWAVERAGE_MODE:
			config->hardwareAverageMode			= (lpadc_hardware_average_mode_t)data;
			break;
		case ADC_CONVCMD_PARAM_SAMPLE_TIMER:
			config->sampleTimeMode				= (lpadc_sample_time_mode_t)data;
			break;
		case ADC_CONVCMD_PARAM_HWCOMPARE_MODE:
			config->hardwareCompareMode			= (lpadc_hardware_compare_mode_t)data;
			break;
		case ADC_CONVCMD_PARAM_HWCOMPARE_HIGH:
			config->hardwareCompareValueHigh	= data;
			break;
		case ADC_CONVCMD_PARAM_HWCOMPARE_LOW:
			config->hardwareCompareValueLow		= data;
			break;
		case ADC_CONVCMD_PARAM_RESOLUTION_MODE:
			config->conversionResolutionMode	= (lpadc_conversion_resolution_mode_t)data;
			break;
		case ADC_CONVCMD_PARAM_WAIT_TRIGGER:
			config->enableWaitTrigger			= (bool)data;
			break;
		default:
			break;
	}
}

//-------------------------------------------------------------------------------------------------------------------
//	@brief		ADC 获取触发信号默认配置
//	@param		config			配置结构体指针
//	Sample usage:				zf_adc_convtrigger_get_default_config(config);
//-------------------------------------------------------------------------------------------------------------------
void zf_adc_convtrigger_get_default_config (lpadc_conv_trigger_config_t *config)
{
//	config->targetCommandId				= 0U;																			// 这个变量写入到 TCTRL 的 [27:24]TCMD 寄存器 选择触发命令
//	config->delayPower					= 0U;																			// 这个变量写入到 TCTRL 的 [19:16]TDLY 寄存器 触发延迟选择
//	config->priority					= 0U;																			// 这个变量写入到 TCTRL 的 [11:8]TPRI 寄存器 触发优先级设置
//	config->enableHardwareTrigger		= false;																		// 是否使能硬件触发信号 16 个 Trigger 的各自硬件触发信号使能
//	config->channelAFIFOSelect			= 0U;																			// 选择 channel A 关联 FIFO 0/1
//	config->channelBFIFOSelect			= 0U;																			// 选择 channel B 关联 FIFO 0/1

	LPADC_GetDefaultConvTriggerConfig(config);
}

//-------------------------------------------------------------------------------------------------------------------
//	@brief		ADC 触发信号配置参数修改
//	@param		config			配置结构体指针
//	@param		index			指定修改参数索引
//	@param		data			参数值
//	Sample usage:				zf_adc_convtrigger_param_set(&config, ADC_PARAM_DOZE_MODE, ADC_DOZE_MODE_ENANLE);
//-------------------------------------------------------------------------------------------------------------------
void zf_adc_convtrigger_param_set (lpadc_conv_trigger_config_t *config, adc_convtrigger_param_list index, uint32_t data)
{
	switch(index)
	{
		case ADC_CONVTRIGGER_PARAM_CMD_ID:
			config->targetCommandId				= data;
			break;
		case ADC_CONVTRIGGER_PARAM_DELAY_POWER:
			config->delayPower					= data;
			break;
		case ADC_CONVTRIGGER_PARAM_PRIORITY:
			config->priority					= data;
			break;
		case ADC_CONVTRIGGER_PARAM_CHA_FIFOSET:
			config->channelAFIFOSelect			= (adc_fifoset_list)data;
			break;
		case ADC_CONVTRIGGER_PARAM_CHB_FIFOSET:
			config->channelBFIFOSelect			= (adc_fifoset_list)data;
			break;
		case ADC_CONVTRIGGER_PARAM_HWTRIGGER:
			config->enableHardwareTrigger		= (bool)data;
			break;
		default:
			break;
	}
}

//-------------------------------------------------------------------------------------------------------------------
//	@brief		ADC 初始化
//	@param		config			配置结构体指针
//	Sample usage:				zf_adc_init(&config);
//-------------------------------------------------------------------------------------------------------------------
void zf_adc_init (lpadc_config_t *config)
{
	CLOCK_SetClkDiv(kCLOCK_DivAdcAsyncClk, 16U, true);																	// 这里是 ADC 设置分频 其实只能写入 3bit 也就是 8 分频 写 16 也是 8 分频
	CLOCK_AttachClk(kMAIN_CLK_to_ADC_CLK);																				// 把主时钟导入 ADC 这样就是 150 Mhz / 8 = 18.75 Mhz

	POWER_DisablePD(kPDRUNCFG_PD_LDOGPADC);

	LPADC_Init(ADC0, config);

	LPADC_DoOffsetCalibration(ADC0);																					// 自行校准零偏
	LPADC_DoAutoCalibration(ADC0);																						// 自动校准
}

//-------------------------------------------------------------------------------------------------------------------
//	@brief		ADC 默认初始化
//	Sample usage:				zf_adc_default_init();
//-------------------------------------------------------------------------------------------------------------------
void zf_adc_default_init (void)
{
	lpadc_config_t adc_config;
	CLOCK_SetClkDiv(kCLOCK_DivAdcAsyncClk, 16U, true);																	// 这里是 ADC 设置分频 其实只能写入 3bit 也就是 8 分频 写 16 也是 8 分频
	CLOCK_AttachClk(kMAIN_CLK_to_ADC_CLK);																				// 把主时钟导入 ADC 这样就是 150 Mhz / 8 = 18.75 Mhz

	POWER_DisablePD(kPDRUNCFG_PD_LDOGPADC);

	zf_adc_get_default_config(&adc_config);
	LPADC_Init(ADC0, &adc_config);																						// 初始化 ADC
	LPADC_DoOffsetCalibration(ADC0);																					// 自行校准零偏
	LPADC_DoAutoCalibration(ADC0);																						// 自动校准
}

//-------------------------------------------------------------------------------------------------------------------
//	@brief		指定通道 ADC 采样初始化
//	@param		ch_index					指定通道
//	@param		adc_convtrigger_config		信号设置结构体
//	@param		adc_convcmd_config			命令设置结构体
//	Sample usage:				zf_adc_sample_init(ADC_ASIDE_CH0, &adc_convtrigger_config, &adc_convcmd_config);
//	@note			这里会开启 ADC 默认开启预启动 方便后续工作
//					相对应的会增加功耗 徒增功耗 * 1 用户可以通过参数设置进行修改
//-------------------------------------------------------------------------------------------------------------------
void zf_adc_sample_init (adc_channel_list ch_index, lpadc_conv_trigger_config_t adc_convtrigger_config, lpadc_conv_command_config_t adc_convcmd_config)
{
	assert(ch_index <= ADC_BSIDE_CH4);
	adc_convcmd_config.sampleChannelMode		= ((0x10 & ch_index)>>4);												// 打开对应管脚的 ADC 组别
	adc_convcmd_config.channelNumber			= ((0x0f & ch_index));													// 打开对应管脚的 ADC 通道
	LPADC_SetConvCommandConfig(ADC0, ((0x0f & ch_index)+1), &adc_convcmd_config);										// 哪个通道就哪个 CMD

	adc_convtrigger_config.targetCommandId		= ((0x0f & ch_index)+1);												// 哪个通道就哪个 CMD

	// 原本按照手册来说 这么写是对的 但实际测试并不能符合手册描述 各位请慎重 实际调试请多注意
	// adc_convtrigger_config.channelAFIFOSelect	= ADC_FIFOSET_0;													// 一律 A 组关联 FIFO0
	// adc_convtrigger_config.channelBFIFOSelect	= ADC_FIFOSET_1;													// 一律 B 组关联 FIFO1

	// 2020.05.19	实际测试时 单独转换 A/B-side channel 时只有 channelAFIFOSelect 参数起作用 用于指定对应 FIFO
	// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!		但请注意 同时转换  A/B-side channel 时			!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
	// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!	channelAFIFOSelect 指定 A-side channel 对应 FIFO		!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
	// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!	channelBFIFOSelect 指定 B-side channel 对应 FIFO		!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
	adc_convtrigger_config.channelAFIFOSelect	= ADC_FIFOSET_0;														// 于是由于都是单独转换 就都放 FIFO0 里

	LPADC_SetConvTriggerConfig(ADC0, ((0x0f & ch_index)), &adc_convtrigger_config);										// 哪个通道就哪个 TRIGGER
}

//-------------------------------------------------------------------------------------------------------------------
//	@brief		ADC 默认初始化通道
//	@param		ch_index					指定通道
//	Sample usage:				zf_adc_sample_default_init(ADC_ASIDE_CH0);
//-------------------------------------------------------------------------------------------------------------------
void zf_adc_sample_default_init (adc_channel_list ch_index)
{
	assert(ch_index <= ADC_BSIDE_CH4);
	lpadc_conv_trigger_config_t		adc_convtrigger_config;
	lpadc_conv_command_config_t		adc_convcmd_config;

	if(!adc_init)
	{
		zf_adc_default_init();
		adc_init = true;
	}

	LPADC_GetDefaultConvCommandConfig(&adc_convcmd_config);
	adc_convcmd_config.sampleChannelMode		= ((0x10 & ch_index)>>4);												// 打开对应管脚的 ADC 组别
	adc_convcmd_config.channelNumber			= ((0x0f & ch_index));													// 打开对应管脚的 ADC 通道
	adc_convcmd_config.conversionResolutionMode	= (lpadc_conversion_resolution_mode_t)ADC_RESOLUTION_MODE_16BIT;		// 选择 16 bit 精度
	LPADC_SetConvCommandConfig(ADC0, ((0x0f & ch_index)+1), &adc_convcmd_config);										// 哪个通道就哪个 CMD

	LPADC_GetDefaultConvTriggerConfig(&adc_convtrigger_config);
	adc_convtrigger_config.targetCommandId		= ((0x0f & ch_index)+1);												// 哪个通道就哪个 CMD

	// 原本按照手册来说 这么写是对的 但实际测试并不能符合手册描述 各位请慎重 实际调试请多注意
	// adc_convtrigger_config.channelAFIFOSelect	= ADC_FIFOSET_0;													// 一律 A 组关联 FIFO0
	// adc_convtrigger_config.channelBFIFOSelect	= ADC_FIFOSET_1;													// 一律 B 组关联 FIFO1

	// 2020.05.19	实际测试时 单独转换 A/B-side channel 时只有 channelAFIFOSelect 参数起作用 用于指定对应 FIFO
	// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!		但请注意 同时转换  A/B-side channel 时			!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
	// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!	channelAFIFOSelect 指定 A-side channel 对应 FIFO		!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
	// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!	channelBFIFOSelect 指定 B-side channel 对应 FIFO		!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
	adc_convtrigger_config.channelAFIFOSelect	= ADC_FIFOSET_0;														// 于是由于都是单独转换 就都放 FIFO0 里

	LPADC_SetConvTriggerConfig(ADC0, ((0x0f & ch_index)), &adc_convtrigger_config);										// 哪个通道就哪个 TRIGGER
}

//-------------------------------------------------------------------------------------------------------------------
//	@brief		ADC 默认初始化差分通道
//	@param		ch_index					指定通道
//	Sample usage:				zf_adc_diff_sample_init(ADC_DIFF_CH0);
//-------------------------------------------------------------------------------------------------------------------
void zf_adc_diff_sample_init (adc_channel_list ch_index)
{
	assert(ch_index > ADC_BSIDE_CH4);
	lpadc_conv_trigger_config_t		adc_convtrigger_config;
	lpadc_conv_command_config_t		adc_convcmd_config;

	if(!adc_init)
	{
		zf_adc_default_init();
		adc_init = true;
	}

	LPADC_GetDefaultConvCommandConfig(&adc_convcmd_config);
	adc_convcmd_config.sampleChannelMode		= kLPADC_SampleChannelDiffBothSide;										// 比较模式
	adc_convcmd_config.channelNumber			= ((0x0f & ch_index));													// 打开对应管脚的 ADC 通道
	adc_convcmd_config.conversionResolutionMode	= (lpadc_conversion_resolution_mode_t)ADC_RESOLUTION_MODE_16BIT;		// 选择 16 bit 精度
	LPADC_SetConvCommandConfig(ADC0, ((0x0f & ch_index)+1), &adc_convcmd_config);										// 哪个通道就哪个 CMD

	LPADC_GetDefaultConvTriggerConfig(&adc_convtrigger_config);
	adc_convtrigger_config.targetCommandId		= ((0x0f & ch_index)+1);												// 哪个通道就哪个 CMD

	// 原本按照手册来说 这么写是对的 但实际测试并不能符合手册描述 各位请慎重 实际调试请多注意
	// adc_convtrigger_config.channelAFIFOSelect	= ADC_FIFOSET_0;													// 一律 A 组关联 FIFO0
	// adc_convtrigger_config.channelBFIFOSelect	= ADC_FIFOSET_1;													// 一律 B 组关联 FIFO1

	// 2020.05.19	实际测试时 单独转换 A/B-side channel 时只有 channelAFIFOSelect 参数起作用 用于指定对应 FIFO
	// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!		但请注意 同时转换  A/B-side channel 时			!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
	// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!	channelAFIFOSelect 指定 A-side channel 对应 FIFO		!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
	// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!	channelBFIFOSelect 指定 B-side channel 对应 FIFO		!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
	adc_convtrigger_config.channelAFIFOSelect	= ADC_FIFOSET_0;														// 于是由于都是单独转换 就都放 FIFO0 里

	LPADC_SetConvTriggerConfig(ADC0, ((0x0f & ch_index)), &adc_convtrigger_config);										// 哪个通道就哪个 TRIGGER
}

//-------------------------------------------------------------------------------------------------------------------
//	@brief		ADC 默认初始化通道
//	@param		ch_index					指定通道
//	Sample usage:				zf_adc_sample_default_init(ADC_ASIDE_CH0);
//-------------------------------------------------------------------------------------------------------------------
void zf_adc_cpu_temp_init (void)
{
	lpadc_conv_trigger_config_t		adc_convtrigger_config;
	lpadc_conv_command_config_t		adc_convcmd_config;

	if(!adc_init)
	{
		zf_adc_default_init();
		adc_init = true;
	}

	LPADC_GetDefaultConvCommandConfig(&adc_convcmd_config);
	adc_convcmd_config.sampleChannelMode			= kLPADC_SampleChannelSingleEndSideA;																// 温度传感器应设置 CMDLT[CTYPE] = 0x2
	adc_convcmd_config.channelNumber				= 26;																// 26 通道对应温度传感器
	adc_convcmd_config.hardwareAverageMode			= kLPADC_HardwareAverageCount128;																// 温度传感器应设置 CMDHT[AVGS] = 0x7
	adc_convcmd_config.loopCount					= 0x03;																// 温度传感器应设置 CMDHT[LOOP] = 0x3
	adc_convcmd_config.enableAutoChannelIncrement	= 0x00;																// 温度传感器应设置 CMDHT[LWI] = 0x0
	adc_convcmd_config.sampleTimeMode				= kLPADC_SampleTimeADCK131;																// 温度传感器应设置 CMDHT[STS] = 0x7
	adc_convcmd_config.hardwareCompareMode			= 0x00;																// 温度传感器应设置 CMDHT[CMPEN] = 0x0
	adc_convcmd_config.conversionResolutionMode	= (lpadc_conversion_resolution_mode_t)ADC_RESOLUTION_MODE_16BIT;		// 选择 16 bit 精度
	LPADC_SetConvCommandConfig(ADC0, ((0x0f & ADC_CPU_TEMP)+1), &adc_convcmd_config);										// 哪个通道就哪个 CMD

	LPADC_GetDefaultConvTriggerConfig(&adc_convtrigger_config);
	adc_convtrigger_config.targetCommandId		= ((0x0f & ADC_CPU_TEMP)+1);												// 哪个通道就哪个 CMD

	// 原本按照手册来说 这么写是对的 但实际测试并不能符合手册描述 各位请慎重 实际调试请多注意
	// adc_convtrigger_config.channelAFIFOSelect	= ADC_FIFOSET_0;													// 一律 A 组关联 FIFO0
	// adc_convtrigger_config.channelBFIFOSelect	= ADC_FIFOSET_1;													// 一律 B 组关联 FIFO1

	// 2020.05.19	实际测试时 单独转换 A/B-side channel 时只有 channelAFIFOSelect 参数起作用 用于指定对应 FIFO
	// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!		但请注意 同时转换  A/B-side channel 时			!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
	// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!	channelAFIFOSelect 指定 A-side channel 对应 FIFO		!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
	// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!	channelBFIFOSelect 指定 B-side channel 对应 FIFO		!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
	adc_convtrigger_config.channelAFIFOSelect	= ADC_FIFOSET_0;														// 于是由于都是单独转换 就都放 FIFO0 里

	LPADC_SetConvTriggerConfig(ADC0, ((0x0f & ADC_CPU_TEMP)), &adc_convtrigger_config);										// 哪个通道就哪个 TRIGGER
}

//-------------------------------------------------------------------------------------------------------------------
//	@brief		ADC 通道获取电压数值
//	@param		ch_index					指定通道
//	Sample usage:				uint16_t value = zf_adc_get_voltage(ADC_ASIDE_CH0);
//-------------------------------------------------------------------------------------------------------------------
uint16_t zf_adc_get_voltage (adc_channel_list ch_index)
{
	assert(ch_index <= ADC_BSIDE_CH4);
	lpadc_conv_result_t config;
	LPADC_DoSoftwareTrigger(ADC0, (0x00000001 << ((0x0f & ch_index))));													// 产生对应管脚的软件 trigger
	while (!LPADC_GetConvResult(ADC0, &config, 0));																		// 等待转换完成
	return config.convValue;																							// 输出
}

//-------------------------------------------------------------------------------------------------------------------
//	@brief		ADC 通道获取电压差值 输出一个16位有符号数
//	@param		ch_index					指定通道
//	Sample usage:				int16_t value = zf_adc_get_diff_voltage(ADC_DIFF_CH0);
//-------------------------------------------------------------------------------------------------------------------
int16_t zf_adc_get_diff_voltage (adc_channel_list ch_index)
{
	assert(ch_index > ADC_BSIDE_CH4);
	lpadc_conv_result_t config;
	LPADC_DoSoftwareTrigger(ADC0, (0x00000001 << ((0x0f & ch_index))));													// 产生对应管脚的软件 trigger
	while (!LPADC_GetConvResult(ADC0, &config, 0));																		// 等待转换完成
	return config.convValue;																							// 输出
}

//-------------------------------------------------------------------------------------------------------------------
//	@brief		获取 CPU 温度
//	Sample usage:				float temp = zf_adc_get_cpu_temp();
//-------------------------------------------------------------------------------------------------------------------
float zf_adc_get_cpu_temp (void)
{
	bool flag = false;
	lpadc_conv_result_t convResultStruct;
	uint16_t Vbe1            = 0U;
	uint16_t Vbe8            = 0U;
	uint32_t convResultShift = 0U;
	float parameterSlope     = FSL_FEATURE_LPADC_TEMP_PARAMETER_A;
	float parameterOffset    = FSL_FEATURE_LPADC_TEMP_PARAMETER_B;
	float parameterAlpha     = FSL_FEATURE_LPADC_TEMP_PARAMETER_ALPHA;
	float temperature        = -273.15f; /* Absolute zero degree as the incorrect return value. */

	LPADC_DoSoftwareTrigger(ADC0, (0x00000001 << ((0x0f & ADC_CPU_TEMP))));

	if ((uint32_t)kLPADC_ConversionResolutionStandard ==
	((ADC0->CMD[ADC_CPU_TEMP].CMDL & ADC_CMDL_MODE_MASK) >> ADC_CMDL_MODE_SHIFT))
	{
		convResultShift = 3U;
	}

	while (!LPADC_GetConvResult(ADC0, &convResultStruct, 0)){}
	while (!LPADC_GetConvResult(ADC0, &convResultStruct, 0)){}

	while(flag != true)
	{
		flag = LPADC_GetConvResult(ADC0, &convResultStruct, 0);
	}
	if (flag)
	{
		flag = false;
		Vbe1 = convResultStruct.convValue >> convResultShift;
		while(flag != true)
		{
			flag = LPADC_GetConvResult(ADC0, &convResultStruct, 0);
		}
		if (flag)
		{
			flag = false;
			Vbe8 = convResultStruct.convValue >> convResultShift;
			/* Final temperature = A*[alpha*(Vbe8-Vbe1)/(Vbe8 + alpha*(Vbe8-Vbe1))] - B. */
			temperature = parameterSlope * (parameterAlpha * ((float)Vbe8 - (float)Vbe1) /
				((float)Vbe8 + parameterAlpha * ((float)Vbe8 - (float)Vbe1))) - parameterOffset;
		}
	}

	return temperature;
}

